
#ifndef __net_sdlH__
#define __net_sdlH__

#include "net_socket.h"

#ifdef NET_SDL

#include "loggable.h"
#include <SDL_net.h>

namespace WtfEngine {
	typedef struct IpAddress{
		unsigned int	Value;
		
		explicit IpAddress(unsigned int v) {
			Value = v;
		};
		IpAddress(unsigned char a, unsigned char b, unsigned char c, unsigned char d) {
			Value = (a << 24) + (b << 16) + (c << 8) + d;
		};
		
		operator unsigned int () {
			return Value;
		};
	} tIpAddress;
	typedef unsigned short				tPort;
	
	
	/**
	 * Generic SDL socket class. Methods are implemented for either
	 * TCP or UDP.
	 **/
	class Socket: public virtual ISocket, public GcObject
	{
		protected:
			tIpAddress		mIpAddress;
			tPort			mPort;
			tStatus			mStatus;
			
		public:
			Socket(const IPaddress& ip);
			Socket(tIpAddress ip, tPort port);
			virtual ~Socket();
			
			virtual void Connect();
			virtual void Disconnect();

			virtual void AddToSet(SDLNet_SocketSet& set) = 0;
			virtual void RemoveFromSet(SDLNet_SocketSet& set) = 0;
			
			virtual bool CheckData() = 0;
			
			tStatus getStatus() {
				return mStatus;
			};

			GC_AUTOSIZE(Socket);
	};
	
	
	/**
	 * TCP guarantees the correctness of packets sent, at
	 * a cost of performance.
	 **/
	class TcpSocket: public Socket
	{
		TCPsocket		mSocket;
		
		public:
			explicit TcpSocket(const TCPsocket& socket);
			TcpSocket(tIpAddress ip, tPort port);
			~TcpSocket();
			
			void Connect();
			void Disconnect();
			
			void			SendPacket(const IPacket::tRef& rPacket);
			IPacket::tRef	RecvPacket();

			void AddToSet(SDLNet_SocketSet& set);
			void RemoveFromSet(SDLNet_SocketSet& set);
			
			bool CheckData();
		
		GC_OBJECT(TcpSocket, sizeof(TcpSocket) + sizeof(_TCPsocket));
	};
	
	
	/**
	 * UDP provides unreliable, but faster transmission of packets. They may
	 * arrive damaged, out of order, or not at all.
	 **/
	class UdpSocket: public Socket
	{
		UDPsocket		mSocket;
		
		public:
			UdpSocket(tIpAddress ip, tPort port);
			~UdpSocket();
			
			void AddToSet(SDLNet_SocketSet& set);
			void RemoveFromSet(SDLNet_SocketSet& set);
			
			bool CheckData();
			
			tStatus getStatus();
		
			GC_OBJECT(UdpSocket, sizeof(UdpSocket) + sizeof(_UDPsocket));
	};
	
	
	class NetworkManager : public Task<NetworkManager>, public Loggable<NetworkManager> {
		static const int MaxSockets = 32;
		
		std::list<Socket::tRef>		mSockets;
		SDLNet_SocketSet			mSocketSet;
		
		public:
			NetworkManager();
			
			/// Adds a socket to the list of active sockets, to
			/// be monitored for incoming data
			void AddSocket(const ISocket::tRef& rSocket);
			
			/// Removes a socket from the list of active sockets.
			void RemoveSocket(const ISocket::tRef& rSocket);
		
		protected:
			/// Reads incoming packets, firing events for them.
			void Run();
	};
};

#endif // NET_SDL
#endif
